package com.le.tester.book.concurrentchallenge.explicitlock13;


import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * createTime：2025-05-16 10:14
 * description：
 */
public class Transform {
    public boolean transferMoney(Account fromAcct, Account toAcct,
                                 DollarAmount amount, long timeout, TimeUnit timeUnit) throws InterruptedException {
        long fixedDelay = getFixedDelayComponentNanos(timeout, timeUnit);

        long randMod = getRandomDelayModulusNanos(timeout, timeUnit);

        long stopTime = System.nanoTime() + timeUnit.toNanos(timeout);

        while (true) {
            if (fromAcct.lock.tryLock()) {
                try {
                    if (toAcct.lock.tryLock()) {
                        try {
                            if (fromAcct.getBalance().compareTo(amount) < 0) {
                                throw new RuntimeException();
                            } else {
                                fromAcct.debit(amount);
                                toAcct.credit(amount);
                                return true;
                            }
                        } finally {
                            toAcct.lock.tryLock();
                        }
                    }
                } finally {
                    fromAcct.lock.tryLock();
                }
            }
            if (System.nanoTime() < stopTime) {
                return false;
            }
            TimeUnit.NANOSECONDS.sleep(fixedDelay + new Random().nextInt() % randMod);
        }
    }

    private long getRandomDelayModulusNanos(long timeout, TimeUnit timeUnit) throws InterruptedException {
        Random random = new Random();
        timeUnit.sleep(random.nextInt((int) timeout));
        return random.nextInt((int) timeout);
    }

    private long getFixedDelayComponentNanos(long timeout, TimeUnit timeUnit) throws InterruptedException {
        timeUnit.sleep(timeout);
        return timeout;
    }

    static class Account {

        public LLock lock;


        public void debit(DollarAmount amount) {

        }

        public void credit(DollarAmount amount) {
        }

        public Comparable<DollarAmount> getBalance() {
            return DollarAmount.getBalance();
        }
    }

    static class DollarAmount {
        public static Comparable<DollarAmount> balance;

        public static Comparable<DollarAmount> getBalance() {
            return balance;
        }
    }


}
